# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
from typing import List
from tortoise.expressions import Q
from tortoise.functions import Count
from hypertext import PagingResult
from common.utils.urls import UrlUtil
from common.utils.config import ConfigUtil
from common.models.users import UserModel
from common.models.agents import AgentRobotModel
from common.models.agents import AgentSquareModel
from common.models.agents import AgentRobotCollectModel
from common.models.draws import DrawsRecordsModel
from common.models.draws import DrawsSquareModel
from common.models.draws import DrawsCollectModel
from common.models.video import VideoRecordsModel
from common.models.video import VideoSquareModel
from common.models.video import VideoCollectModel
from common.models.music import MusicRecordsModel
from common.models.music import MusicSquareModel
from common.models.music import MusicCollectModel
from common.models.public import SquareCategoryModel
from apps.api.schemas import square_schema as schema


class SquareService:
    """ 广场服务类 """

    @classmethod
    async def setting(cls) -> List[schema.SquareSettingVo]:
        """
        广场配置参数

        Returns:
            List[schema.SquareSettingVo]

        Author:
            zero
        """
        config = await ConfigUtil.get('square') or {}

        async def create_config_vo(scene: str):
            section: dict = config.get(scene) or {}
            return schema.SquareSettingVo(
                type=scene,
                is_open=int(section.get("is_open", "0")),
                is_user=int(section.get("is_user", "0")),
                name=str(section.get("name", "")),
                title=section.get("title", ""),
                banner=await UrlUtil.to_absolute_url(section.get("banner", ""))
            )

        return [
            await create_config_vo("robot"),
            await create_config_vo("draws"),
            await create_config_vo("video"),
            await create_config_vo("music")
        ]

        # return schema.SquareSettingVo(
        #     robot=await create_config_vo(config.get("robot") or {}),
        #     draws=await create_config_vo(config.get("draws") or {}),
        #     video=await create_config_vo(config.get("video") or {}),
        #     music=await create_config_vo(config.get("music") or {})
        # )

        # robot = await ConfigUtil.get('square', "robot") or {}
        # draws = await ConfigUtil.get('square', "draws") or {}
        # return [
        #     schema.SquareSettingVo(
        #         type="robot",
        #         is_open=int(robot.get("is_open", "0")),
        #         is_user=str(robot.get("is_user", "0")),
        #         name=str(robot.get("name", "")),
        #         title=str(robot.get("title", "")),
        #         banner=await UrlUtil.to_absolute_url(str(draws.get("banner", "")))
        #     ),
        #     schema.SquareSettingVo(
        #         type="draws",
        #         is_open=int(draws.get("is_open", "0")),
        #         is_user=str(draws.get("is_user", "0")),
        #         name=str(draws.get("name", "")),
        #         title=str(draws.get("title", "")),
        #         banner=await UrlUtil.to_absolute_url(str(draws.get("banner", "")))
        #     )
        # ]

    @classmethod
    async def category(cls, scene: str) -> List[schema.SquareCategoryVo]:
        """
        广场分类列表

        Args:
            scene (str): 场景: [robot=智能体,draws=绘画...]

        Returns:
            List[schema.SquareCategoryVo]

        Author:
            zero
        """
        lists = await (SquareCategoryModel
                       .filter(scene=scene)
                       .filter(is_disable=0)
                       .filter(is_delete=0)
                       .order_by("-sort", "-id")
                       .all())

        _lists = [schema.SquareCategoryVo(
            id=0,
            name="全部",
            icon=""
        ), schema.SquareCategoryVo(
            id=-1,
            name="收藏",
            icon=""
        )]

        for item in lists:
            _lists.append(schema.SquareCategoryVo(
                id=item.id,
                name=item.name,
                icon=await UrlUtil.to_absolute_url(item.icon)
            ))
        return _lists

    @classmethod
    async def robot_list(cls, user_id: int, params: schema.SquareSearchIn) -> PagingResult[schema.SquareRobotVo]:
        """
        智能体广场列表

        Args:
            user_id (int): 用户ID
            params (schema.SquareSearchIn): 搜索参数

        Returns:
            PagingResult[schema.SquareRobotVo]

        Author:
            zero
        """
        # 基本条件
        where_robot_ids = None
        if params.keyword:
            robots = await AgentRobotModel.filter(name__icontains=params.keyword, is_delete=0).values("id")
            where_robot_ids = [robots["id"] for robots in robots] or [0]

        # 分类查询
        if params.cate is not None and params.cate == -1:
            # 用户收藏
            where = [Q(user_id=user_id), Q(is_delete=0)]
            if where_robot_ids is not None:
                where.append(Q(robot_id__in=where_robot_ids))

            _model = AgentRobotCollectModel.filter(*where).order_by("-id")
            _pager = await AgentRobotCollectModel.paginate(
                model=_model,
                page_no=params.page_no,
                page_size=params.page_size
            )
        else:
            # 按类目查
            where = [Q(is_delete=0), Q(is_enable=1), Q(audit_status=1)]
            if params.cate is not None and params.cate > 0:
                where.append(Q(cate_id=params.cate))
            if where_robot_ids is not None:
                where.append(Q(robot_id__in=where_robot_ids))

            _model = AgentSquareModel.filter(*where).order_by("-sort")
            _pager = await AgentSquareModel.paginate(
                model=_model,
                page_no=params.page_no,
                page_size=params.page_size
            )

        # 查智能体
        robot_ids = [item["robot_id"] for item in _pager.lists]
        fields = ["id", "user_id", "code", "logo", "name", "intro"]
        robots = await AgentRobotModel.queryRobotDictsById(robot_ids, fields)

        # 查收藏数
        collect_query = await (AgentRobotCollectModel
                               .filter(robot_id__in=robot_ids)
                               .filter(is_delete=0)
                               .annotate(count=Count("robot_id"))
                               .group_by("robot_id")
                               .values_list("robot_id", "count"))
        collect_data = {k: v for k, v in collect_query}

        # 查询用户
        user_ids = [entry['user_id'] for entry in robots.values()]
        users = await UserModel.queryUserDictsById(user_ids)

        # 处理结果
        _lists = []
        for item in _pager.lists:
            robot = robots.get(item["robot_id"]) or {}
            user = users.get(robot.get("user_id")) or {}
            _lists.append(schema.SquareRobotVo(
                code=robot.get("code"),
                name=robot.get("name"),
                logo=await UrlUtil.to_absolute_url(robot.get("logo")),
                intro=robot.get("intro"),
                usage_num=0,
                collect_num=collect_data.get(robot.get("id"), 0),
                user={
                    "sn": user.get("sn", ""),
                    "nickname": user.get("nickname", ""),
                    "avatar": await UrlUtil.to_absolute_url(user.get('avatar', ""))
                }
            ))

        _pager.lists = _lists
        return _pager

    @classmethod
    async def draws_list(cls, user_id: int, params: schema.SquareSearchIn):
        # 用户收藏
        collect_ids = []
        if params.cate is not None and params.cate == -1:
            condition = [Q(user_id=user_id), Q(is_delete=0)]
            if params.keyword:
                draws = await (DrawsRecordsModel
                               .filter(prompt_in__icontains=params.keyword)
                               .filter(source=2)
                               .filter(audit_status=1)
                               .filter(is_enable=1)
                               .filter(is_delete=0)
                               .limit(300)
                               .values("id"))
                condition.append(Q(record_id__in=[item["id"] for item in draws] or [0]))

            _model = DrawsCollectModel.filter(*condition).order_by("-id")
            _pager = await DrawsCollectModel.paginate(
                model=_model,
                page_no=params.page_no,
                page_size=params.page_size
            )
            collect_ids = list(set([item["record_id"] for item in _pager.lists])) or [0]

        # 查询条件
        where = [Q(is_delete=0), Q(is_enable=1), Q(audit_status=1)]
        if collect_ids:
            where.append(Q(id__in=collect_ids))
        else:
            if params.keyword:
                where.append(Q(prompt_in__icontains=params.keyword))

        # 查询数据
        _model = DrawsSquareModel.filter(*where).order_by("-sort", "-id")
        _pager = await DrawsSquareModel.paginate(
            model=_model,
            page_no=params.page_no,
            page_size=params.page_size
        )

        # 查询用户
        user_ids = [entry["operate_id"] for entry in _pager.lists if entry["source"] == 2]
        users = await UserModel.queryUserDictsById(user_ids)

        # 查询收藏
        ids = list(set([entry["record_id"] for entry in _pager.lists]))
        collect_record_ids = []
        if ids:
            collects = await (DrawsCollectModel
                              .filter(record_id__in=ids)
                              .filter(user_id=user_id)
                              .filter(is_delete=0)
                              .values("record_id"))
            collect_record_ids = list(set([item["record_id"] for item in collects]))

        # 处理结果
        _lists = []
        for item in _pager.lists:
            user = users.get(item.get("operate_id")) or {}
            is_collect = True if item["record_id"] in collect_record_ids else False
            _lists.append(schema.SquareDrawsVo(
                code=item.get("draw_code", ""),
                thumbnail=await UrlUtil.to_absolute_url(item.get("thumbnail", "")),
                image_loc=await UrlUtil.to_absolute_url(item.get("image_loc", "")),
                prompt_in=item.get("prompt_in") or "",
                prompt_en=item.get("prompt_en") or "",
                is_collect=is_collect,
                user={
                    "sn": user.get("sn", ""),
                    "nickname": user.get("nickname", ""),
                    "avatar": await UrlUtil.to_absolute_url(user.get('avatar', ""))
                }
            ))

        return _lists

    @classmethod
    async def video_list(cls, user_id: int, params: schema.SquareSearchIn):
        # 用户收藏
        collect_ids = []
        if params.cate is not None and params.cate == -1:
            condition = [Q(user_id=user_id), Q(is_delete=0)]
            if params.keyword:
                draws = await (VideoRecordsModel
                               .filter(prompt_in__icontains=params.keyword)
                               .filter(source=2)
                               .filter(is_enable=1)
                               .filter(is_delete=0)
                               .filter(audit_status=1)
                               .limit(300)
                               .values("id"))
                condition.append(Q(record_id__in=[item["id"] for item in draws] or [0]))

            _model = VideoCollectModel.filter(*condition).order_by("-id")
            _pager = await VideoCollectModel.paginate(
                model=_model,
                page_no=params.page_no,
                page_size=params.page_size
            )
            collect_ids = list(set([item["record_id"] for item in _pager.lists])) or [0]

        # 查询条件
        where = [Q(is_delete=0), Q(is_enable=1), Q(audit_status=1)]
        if collect_ids:
            where.append(Q(id__in=set(collect_ids)))
        else:
            if params.keyword:
                where.append(Q(prompt_in__icontains=str(params.keyword)))

        # 查询数据
        _model = VideoSquareModel.filter(*where).order_by("-sort", "-id")
        _pager = await VideoSquareModel.paginate(
            model=_model,
            page_no=params.page_no,
            page_size=params.page_size
        )

        # 查询用户
        user_ids = [entry[str("operate_id")] for entry in _pager.lists if entry["source"] == 2]
        users = await UserModel.queryUserDictsById(user_ids)

        # 查询收藏
        ids = list(set([entry["record_id"] for entry in _pager.lists]))
        collect_record_ids = []
        if ids:
            collects = await (VideoCollectModel
                              .filter(is_delete=0)
                              .filter(record_id__in=ids)
                              .filter(user_id=user_id)
                              .values("record_id"))
            collect_record_ids = list(set([item["record_id"] for item in collects]))

        # 处理结果
        _lists = []
        for item in _pager.lists:
            user = users.get(item.get("operate_id")) or {}
            is_collect = True if item["record_id"] in collect_record_ids else False
            _lists.append(schema.SquareVideoVo(
                code=item.get("video_code", ""),
                video_url=await UrlUtil.to_absolute_url(item.get("video_url", "")),
                prompt=item.get("prompt") or "",
                is_collect=is_collect,
                user={
                    "sn": user.get("sn", ""),
                    "nickname": user.get("nickname", ""),
                    "avatar": await UrlUtil.to_absolute_url(user.get('avatar', ""))
                }
            ))

        return _lists

    @classmethod
    async def music_list(cls, user_id: int, params: schema.SquareSearchIn):
        # 用户收藏
        collect_ids = []
        if params.cate is not None and params.cate == -1:
            condition = [Q(user_id=user_id), Q(is_delete=0)]
            if params.keyword:
                draws = await (MusicRecordsModel
                               .filter(prompt_in__icontains=params.keyword)
                               .filter(source=2)
                               .filter(is_delete=0)
                               .filter(is_enable=1)
                               .filter(audit_status=1)
                               .limit(300)
                               .values("id"))
                condition.append(Q(record_id__in=[item["id"] for item in draws] or [0]))

            _model = MusicCollectModel.filter(*condition).order_by("-id")
            _pager = await MusicCollectModel.paginate(
                model=_model,
                page_no=params.page_no,
                page_size=params.page_size
            )
            collect_ids = list(set([item["record_id"] for item in _pager.lists])) or [0]

        # 查询条件
        where = [Q(is_delete=0), Q(is_enable=1), Q(audit_status=1)]
        if collect_ids:
            where.append(Q(id__in=collect_ids))
        else:
            if params.keyword:
                where.append(Q(prompt_in__icontains=str(params.keyword)))

        # 查询数据
        _model = MusicSquareModel.filter(*where).order_by("-sort", "-id")
        _pager = await MusicSquareModel.paginate(
            model=_model,
            page_no=params.page_no,
            page_size=params.page_size
        )

        # 查询用户
        user_ids = [entry["operate_id"] for entry in _pager.lists if entry[str("source")] == 2]
        users = await UserModel.queryUserDictsById(user_ids)

        # 查询收藏
        ids = list(set([entry["record_id"] for entry in _pager.lists]))
        collect_record_ids = []
        if ids:
            collects = await (MusicCollectModel
                              .filter(user_id=user_id)
                              .filter(record_id__in=ids)
                              .filter(is_delete=0)
                              .values(str("record_id")))
            collect_record_ids = list(set([item["record_id"] for item in collects]))

        # 处理结果
        _lists = []
        for item in _pager.lists:
            user = users.get(item.get("operate_id")) or {}
            is_collect = True if item["record_id"] in collect_record_ids else False
            _lists.append(schema.SquareMusicVo(
                id=item.get("id"),
                code=item.get("music_code", ""),
                cover_url=await UrlUtil.to_absolute_url(item.get("cover_url", "")),
                audio_url=await UrlUtil.to_absolute_url(item.get("audio_url", "")),
                title=item.get("title"),
                tags=item.get("tags"),
                prompt=item.get("prompt") or "",
                lyric=item.get("lyric") or "",
                duration=item.get("duration"),
                is_collect=is_collect,
                user={
                    "sn": user.get("sn", ""),
                    "nickname": user.get("nickname", ""),
                    "avatar": await UrlUtil.to_absolute_url(user.get('avatar', ""))
                }
            ))

        return _lists

